﻿/*
 * Message
 * 
 * Author: snowdreamist
 * Date: 2011/11/23
 * 
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BitTorrentSharp.BEncoding;
using BitTorrentSharp.Helpers;

namespace BitTorrentSharp.KRPC.Messages
{
    /// <summary>
    /// Message type
    /// </summary>
    public enum MessageType
    {
        Query,
        Response,
        Error
    }

    /// <summary>
    /// Represents a message
    /// </summary>
    public abstract class Message
    {
        #region consts
        /*
         * keys
         */
        internal const string TransactionIDKey = "t";
        internal const string TypeKey = "y";

        #endregion

        #region static
        /// <summary>
        /// Deserialize BDictionary to Message
        /// </summary>
        /// <param name="dict"></param>
        /// <returns></returns>
        public static Message Deserialize(BDictionary dict)
        {
            if (dict == null)
                throw new ArgumentNullException("dict");
            // check type
            if (!dict.ContainsKey(TypeKey))
                throw new ArgumentException("Missing message type information");

            var value = (dict[TypeKey] as BString).ToString();

            if (value == "q")
            {
                var message = new QueryMessage();
                message.InternalDeserialize(dict);
                return message;
            }
            else if (value == "r")
            {
                var message = new ResponseMessage();
                message.InternalDeserialize(dict);
                return message;
            }
            else if (value == "e")
            {
                var message = new ErrorMessage();
                message.InternalDeserialize(dict);
                return message;
            }
            else
            {
                throw new ArgumentException(string.Format("Unknown message type {0}", value));
            }
        }

        #endregion
        /// <summary>
        /// Transaction
        /// </summary>
        public Transaction Transaction { get; protected set; }
        /// <summary>
        /// MessageType
        /// </summary>
        public MessageType Type { get; protected set; }
        /// <summary>
        /// Serialize
        /// </summary>
        /// <returns></returns>
        internal virtual BDictionary Serialize()
        {
            if(this.Transaction == null)
                throw new ArgumentNullException("Transaction");

            BDictionary dict = new BDictionary();

            dict.Add(new BString(TransactionIDKey), new BString(this.Transaction.ToArray()));

            return dict;
        }
        /// <summary>
        /// Deserialize
        /// </summary>
        /// <param name="dict"></param>
        internal virtual void InternalDeserialize(BDictionary dict)
        {
            if (!dict.ContainsKey(TransactionIDKey))
                throw new ArgumentException("Missing Transaction ID");

            BString id = dict[TransactionIDKey] as BString;
            this.Transaction = new Transaction(id.Content);
        }
    }
}
